using System;
using System.Collections.Generic;
using System.Text;

namespace MoEngine
{
    public class CoreComponentCollection : ICollection<CoreComponent>
    {
        protected List<CoreComponent> m_Components = new List<CoreComponent>();
        protected List<CoreComponentDrawable> m_DrawableComponents = new List<CoreComponentDrawable>();

        protected CoreComponent[] m_UpdateList;
        protected CoreComponentDrawable[] m_DrawList;

        protected bool m_bUpdateOrderDirty = true;
        protected bool m_bDrawOrderDirty = true;
        protected bool m_bUpdateListDirty = true;
        protected bool m_bDrawListDirty = true;

        protected static int CompareUpdateOrder(CoreComponent a, CoreComponent b)
        {
            return a.UpdateOrder.CompareTo(b.UpdateOrder);
        }

        protected void VerifyUpdateOrder()
        {
            if (m_bUpdateOrderDirty)
            {
                m_Components.Sort(CompareUpdateOrder);
                m_bUpdateOrderDirty = false;
                m_bUpdateListDirty = true;
            }
        }

        protected static int CompareDrawOrder(CoreComponentDrawable a, CoreComponentDrawable b)
        {
            return a.DrawOrder.CompareTo(b.DrawOrder);
        }

        protected void VerifyDrawOrder()
        {
            if (m_bDrawOrderDirty)
            {
                m_DrawableComponents.Sort(CompareDrawOrder);
                m_bDrawOrderDirty = false;
                m_bDrawListDirty = true;
            }
        }

        protected void VerifyUpdateList()
        {
            if (m_bUpdateListDirty)
            {
                m_UpdateList = new CoreComponent[m_Components.Count];
                m_Components.CopyTo(m_UpdateList);
                m_bUpdateListDirty = false;
            }
        }

        protected void VerifyDrawList()
        {
            if (m_bDrawListDirty)
            {
                m_DrawList = new CoreComponentDrawable[m_DrawableComponents.Count];
                m_DrawableComponents.CopyTo(m_DrawList);
                m_bDrawListDirty = false;
            }
        }

        #region ICollection<CoreComponent> Members
        
        public void Add(CoreComponent item)
        {
            if (!m_Components.Contains(item))
            {
                m_Components.Add(item);
                if (item.UpdateOrder == 0)
                    item.UpdateOrder = m_Components.Count - 1;
                item.UpdateOrderChanged += new EventHandler(OnItemUpdateOrderChanged);
                m_bUpdateOrderDirty = true;
                m_bUpdateListDirty = true;

                CoreComponentDrawable drawableItem = item as CoreComponentDrawable;
                if (drawableItem != null)
                {
                    m_DrawableComponents.Add(drawableItem);
                    if (drawableItem.DrawOrder == 0)
                        drawableItem.DrawOrder = m_DrawableComponents.Count - 1;
                    drawableItem.DrawOrderChanged += new EventHandler(OnItemDrawOrderChanged);
                    m_bDrawOrderDirty = true;
                    m_bDrawListDirty = true;
                }
            }
        }


        void OnItemUpdateOrderChanged(object sender, EventArgs e)
        {
            m_bUpdateOrderDirty = true;
        }

        void OnItemDrawOrderChanged(object sender, EventArgs e)
        {
            m_bDrawOrderDirty = true;
        }

        public void Clear()
        {
            while (m_Components.Count > 0)
            {
                Remove(m_Components[0]);
            }
        }

        public bool Contains(CoreComponent item)
        {
            return m_Components.Contains(item);
        }

        public void CopyTo(CoreComponent[] array, int arrayIndex)
        {
            VerifyUpdateOrder();
            m_Components.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return m_Components.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(CoreComponent item)
        {
            if (m_Components.Remove(item))
            {
                item.UpdateOrderChanged -= OnItemUpdateOrderChanged;
                m_bUpdateListDirty = true;

                CoreComponentDrawable drawableItem = item as CoreComponentDrawable;
                if (drawableItem != null)
                {
                    drawableItem.DrawOrderChanged -= OnItemDrawOrderChanged;
                    m_DrawableComponents.Remove(drawableItem);
                    m_bDrawListDirty = true;
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion

        public IEnumerable<CoreComponentDrawable> DrawList
        {
            get
            {
                VerifyDrawOrder();
                VerifyDrawList();
                return m_DrawList;
            }
        }

        public IEnumerable<CoreComponent> UpdateList
        {
            get
            {
                VerifyUpdateOrder();
                VerifyUpdateList();
                return m_UpdateList;
            }     
        }

        #region IEnumerable<CoreComponent> Members

        public IEnumerator<CoreComponent> GetEnumerator()
        {
            return m_Components.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
}
